# /**
# * Copyright (c) 2022 Beijing Jiaotong University
# * PhotLab is licensed under [Open Source License].
# * You can use this software according to the terms and conditions of the [Open Source License].
# *
# * You may obtain a copy of [Open Source License] at: [https://open.source.license/]
# *
# * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# *
# * See the [Open Source License] for more details.
# */
# /**
# * Author: Shihao Xie
# * Created: Jul. 5, 2022
# * Supported by: National Key Research and Development Program of China
# */
import sys
from phot_server.utils.phot_logger import logger
from phot_server.rpc.main_service.Main import Processor
from thrift.Thrift import TType, TMessageType, TApplicationException
from thrift.transport import TTransport
from thrift.protocol.TBinaryProtocol import TBinaryProtocol
from thrift.protocol.TJSONProtocol import TJSONProtocol


#
# This class is a container that contain all process function of interface function,
# which is the subclass of Processor in MainInterfaceDefinition.main
#
class MainProcessor(Processor):
    # It is process map, which is the mapping of interface function name and its process function.
    # For exmaple _processMap["getLibraryList"] = process_getLibraryList
    # it means the process function of "getLibraryList" is process_getLibraryList
    _processMap = {}

    def __init__(self, handler):
        self._handler = handler
        self._on_message_begin = None

    # _processMap is protected in Processor of MainInterfaceDefinition
    # This method is to add a 'name-function' mapping to _processMap
    def add_mapping(self, name, function):
        self._processMap[name] = function

    # This method prints the item in _processMap
    def print_map(self):
        logger.debug("The mapping in _processMap ===")
        for item in self._processMap.items():
            logger.debug(item)

    def process(self, iprot, oprot):
        (name, type, seqid) = iprot.readMessageBegin()
        if self._on_message_begin:
            self._on_message_begin(name, type, seqid)

        if self.read_attachment_field(iprot, oprot) is False:
            iprot.trans.cstringio_buf.seek(0, 0)
            if isinstance(iprot, TJSONProtocol):
                iprot.resetWriteContext()
                iprot.resetReadContext()
            elif isinstance(iprot, TBinaryProtocol):
                pass
            iprot.readMessageBegin()


        if name not in self._processMap:
            iprot.skip(TType.STRUCT)
            iprot.readMessageEnd()
            x = TApplicationException(TApplicationException.UNKNOWN_METHOD, 'Unknown function %s' % (name))
            oprot.writeMessageBegin(name, TMessageType.EXCEPTION, seqid)
            x.write(oprot)
            oprot.writeMessageEnd()
            oprot.trans.flush()
            return
        else:
            # Data is deserialized by process function
            self._processMap[name](self, seqid, iprot, oprot)
        return True

    def read_attachment_field(self, iprot, oprot):
        if iprot._fast_decode is not None \
                and isinstance(iprot.trans, TTransport.CReadableTransport) \
                and self.thrift_spec is not None:
            iprot._fast_decode(self, iprot, [self.__class__, self.thrift_spec])
            return

        iprot.readStructBegin()
        (fname, ftype, fid) = iprot.readFieldBegin()

        if ftype == TType.STOP:
            return False

        if fid != 0:
            return False

        if ftype == TType.MAP:
            # read map
            header = {}
            (key_type, value_type, map_size) = iprot.readMapBegin()
            for map_index in range(map_size):
                map_key = iprot.readString().decode('utf-8', errors='replace') \
                    if sys.version_info[0] == 2 else iprot.readString()
                map_value = iprot.readString().decode('utf-8', errors='replace') \
                    if sys.version_info[0] == 2 else iprot.readString()
                header[map_key] = map_value
            iprot.readMapEnd()
            self._handler.set_headers(header)
            logger.debug("\033[32m Attach header map: {} \033[0m".format(str(header)))
            iprot.readFieldEnd()
            iprot.readStructEnd()
            return True
        else:
            return False